macos: support ARM/PowerPC time conversion for DisplayLink times
authorChristian Hergert <chergert@redhat.com>
Mon, 27 Jul 2020 19:49:57 +0000 (12:49 -0700)
committerChristian Hergert <chergert@redhat.com>
Mon, 27 Jul 2020 19:49:57 +0000 (12:49 -0700)
When converting DisplayLink frame presentation times, we need to take into
account the arch-specific types. This tracks changes in GNOME/GLib!1566 so
that precision is not lost.

gdk/macos/gdkdisplaylinksource.c
meson.build

index 36decbbaad60c36c7fc76e9e4a64570b682d97b7..76c57feaeb96e87da710a955da96e0d845a74d3a 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "gdkmacoseventsource-private.h"
 
-static gint64 host_to_frame_clock_time (gint64 host_time);
+static gint64 host_to_frame_clock_time (gint64 val);
 
 static gboolean
 gdk_display_link_source_prepare (GSource *source,
@@ -203,52 +203,40 @@ gdk_display_link_source_new (void)
 }
 
 static gint64
-host_to_frame_clock_time (gint64 host_time)
+host_to_frame_clock_time (gint64 val)
 {
-  static mach_timebase_info_data_t timebase_info;
+  /* NOTE: Code adapted from GLib's g_get_monotonic_time(). */
 
-  /*
-   * NOTE:
-   *
-   * This code is taken from GLib to match g_get_monotonic_time().
-   */
-  if (G_UNLIKELY (timebase_info.denom == 0))
+  mach_timebase_info_data_t timebase_info;
+
+  /* we get nanoseconds from mach_absolute_time() using timebase_info */
+  mach_timebase_info (&timebase_info);
+
+  if (timebase_info.numer != timebase_info.denom)
     {
-      /* This is a fraction that we must use to scale
-       * mach_absolute_time() by in order to reach nanoseconds.
-       *
-       * We've only ever observed this to be 1/1, but maybe it could be
-       * 1000/1 if mach time is microseconds already, or 1/1000 if
-       * picoseconds.  Try to deal nicely with that.
-       */
-      mach_timebase_info (&timebase_info);
-
-      /* We actually want microseconds... */
-      if (timebase_info.numer % 1000 == 0)
-        timebase_info.numer /= 1000;
-      else
-        timebase_info.denom *= 1000;
-
-      /* We want to make the numer 1 to avoid having to multiply... */
-      if (timebase_info.denom % timebase_info.numer == 0)
-        {
-          timebase_info.denom /= timebase_info.numer;
-          timebase_info.numer = 1;
-        }
-      else
-        {
-          /* We could just multiply by timebase_info.numer below, but why
-           * bother for a case that may never actually exist...
-           *
-           * Plus -- performing the multiplication would risk integer
-           * overflow.  If we ever actually end up in this situation, we
-           * should more carefully evaluate the correct course of action.
-           */
-          mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */
-          g_error ("Got weird mach timebase info of %d/%d.  Please file a bug against GLib.",
-                   timebase_info.numer, timebase_info.denom);
-        }
+#ifdef HAVE_UINT128_T
+      val = ((__uint128_t) val * (__uint128_t) timebase_info.numer) / timebase_info.denom / 1000;
+#else
+      guint64 t_high, t_low;
+      guint64 result_high, result_low;
+
+      /* 64 bit x 32 bit / 32 bit with 96-bit intermediate
+       * algorithm lifted from qemu */
+      t_low = (val & 0xffffffffLL) * (guint64) timebase_info.numer;
+      t_high = (val >> 32) * (guint64) timebase_info.numer;
+      t_high += (t_low >> 32);
+      result_high = t_high / (guint64) timebase_info.denom;
+      result_low = (((t_high % (guint64) timebase_info.denom) << 32) +
+                    (t_low & 0xffffffff)) /
+                   (guint64) timebase_info.denom;
+      val = ((result_high << 32) | result_low) / 1000;
+#endif
+    }
+  else
+    {
+      /* nanoseconds to microseconds */
+      val = val / 1000;
     }
 
-  return host_time / timebase_info.denom;
+  return val;
 }
index 43208bc669d7246eca13479301149a30542d9e1b..3ab900eb06541e2d71add135e8077834efba1f09 100644 (file)
@@ -207,6 +207,17 @@ foreach func : check_functions
   endif
 endforeach
 
+# Check for __uint128_t (gcc) by checking for 128-bit division
+uint128_t_src = '''int main() {
+static __uint128_t v1 = 100;
+static __uint128_t v2 = 10;
+static __uint128_t u;
+u = v1 / v2;
+}'''
+if cc.compiles(uint128_t_src, name : '__uint128_t available')
+  cdata.set('HAVE_UINT128_T', 1)
+endif
+
 # Disable deprecation checks for all libraries we depend on on stable branches.
 # This is so newer versions of those libraries don't cause more warnings with
 # a stable GTK version.